/**
 * Copyright (c) 2018-2022, NXOS Development Team
 * SPDX-License-Identifier: Apache-2.0
 * 
 * Contains: fat file system
 * 
 * Change Logs:
 * Date           Author            Notes
 * 2022-08-15     JasonHu           Port from xboot
 */

/*
 * kernel/vfs/fat/fat.c
 *
 * Copyright(c) 2007-2022 Jianjun Jiang <8192542@qq.com>
 * Official site: http://xboot.org
 * Mobile phone: +86-18665388956
 * QQ: 8192542
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#ifndef __FS_FAT_H__
#define __FS_FAT_H__

#include <nxos/fs.h>

#include <nxos/time.h>

/*
 * Important offsets
 */
#define FAT_BOOTSECTOR_OFFSET	(0x000)

/*
 * Enumeration of possible values for Media Type field in boot sector
 */
enum fat_media_type_t {
	FAT_DOUBLE_SIDED_1_44_MB	= 0xF0,
	FAT_FIXED_DISK				= 0xF8,
	FAT_DOUBLE_SIDED_720_KB		= 0xF9,
	FAT_SINGLE_SIDED_320_KB		= 0xFA,
	FAT_DOUBLE_SIDED_640_KB		= 0xFB,
	FAT_SINGLE_SIDED_180_KB		= 0xFC,
	FAT_DOUBLE_SIDED_360_KB		= 0xFD,
	FAT_SINGLE_SIDED_160_KB		= 0xFE,
	FAT_DOUBLE_SIDED_320_KB		= 0xFF,
};

/*
 * Enumeration of FAT types
 */
enum fat_type_t {
	FAT_TYPE_12					= 12,
	FAT_TYPE_16					= 16,
	FAT_TYPE_32					= 32,
};

/*
 * Enumeration of types of cluster in FAT12 table
 */
enum fat12_cluster_type_t {
	FAT12_FREE_CLUSTER			= 0x000,
	FAT12_RESERVED1_CLUSTER		= 0x001,
	FAT12_RESERVED2_CLUSTER		= 0xFF0,
	FAT12_BAD_CLUSTER			= 0xFF7,
	FAT12_LAST_CLUSTER			= 0xFF8,
};

/*
 * Enumeration of types of cluster in FAT16 table
 */
enum fat16_cluster_type_t {
	FAT16_FREE_CLUSTER			= 0x0000,
	FAT16_RESERVED1_CLUSTER		= 0x0001,
	FAT16_RESERVED2_CLUSTER		= 0xFFF0,
	FAT16_BAD_CLUSTER			= 0xFFF7,
	FAT16_LAST_CLUSTER			= 0xFFF8,
};

/*
 * Enumeration of types of cluster in FAT32 table
 */
enum fat32_cluster_type_t {
	FAT32_FREE_CLUSTER			= 0x00000000,
	FAT32_RESERVED1_CLUSTER		= 0x00000001,
	FAT32_RESERVED2_CLUSTER		= 0x0FFFFFF0,
	FAT32_BAD_CLUSTER			= 0x0FFFFFF7,
	FAT32_LAST_CLUSTER			= 0x0FFFFFF8,
};

/*
 * Extended boot sector information for FAT12/FAT16
 */
struct fat_bootsec_ext16_t {
	NX_U8 drive_number;
	NX_U8 reserved;
	NX_U8 extended_signature;
	NX_U32 serial_number;
	NX_U8 volume_label[11];
	NX_U8 fs_type[8];
	NX_U8 boot_code[448];
	NX_U16 boot_sector_signature;
} NX_PACKED;

/*
 * Extended boot sector information for FAT32
 */
struct fat_bootsec_ext32_t {
	NX_U32 sectors_per_fat;
	NX_U16 fat_flags;
	NX_U16 version;
	NX_U32 root_directory_cluster;
	NX_U16 fs_info_sector;
	NX_U16 boot_sector_copy;
	NX_U8 reserved1[12];
	NX_U8 drive_number;
	NX_U8 reserved2;
	NX_U8 extended_signature;
	NX_U32 serial_number;
	NX_U8 volume_label[11];
	NX_U8 fs_type[8];
	NX_U8 boot_code[420];
	NX_U16 boot_sector_signature;
} NX_PACKED;

/*
 * Boot sector information for FAT12 / FAT16 / FAT32
 */
struct fat_bootsec_t {
	NX_U8 jump[3];
	NX_U8 oem_name[8];
	NX_U16 bytes_per_sector;
	NX_U8 sectors_per_cluster;
	NX_U16 reserved_sector_count;
	NX_U8 number_of_fat;
	NX_U16 root_entry_count;
	NX_U16 total_sectors_16;
	NX_U8 media_type;
	NX_U16 sectors_per_fat;
	NX_U16 sectors_per_track;
	NX_U16 number_of_heads;
	NX_U32 hidden_sector_count;
	NX_U32 total_sectors_32;
	union {
		struct fat_bootsec_ext16_t e16;
		struct fat_bootsec_ext32_t e32;
	} ext;
} NX_PACKED;

/*
 * Directory entry attributes
 */
#define	FAT_DIRENT_READONLY		0x01
#define	FAT_DIRENT_HIDDEN		0x02
#define	FAT_DIRENT_SYSTEM		0x04
#define	FAT_DIRENT_VOLLABLE		0x08
#define	FAT_DIRENT_SUBDIR		0x10
#define	FAT_DIRENT_ARCHIVE		0x20
#define	FAT_DIRENT_DEVICE		0x40
#define	FAT_DIRENT_UNUSED		0x80

/*
 * Directory entry information for FAT12 / FAT16 / FAT32
 */
struct fat_dirent_t {
	NX_U8 dos_file_name[8];
	NX_U8 dos_extension[3];
	NX_U8 file_attributes;
	NX_U8 reserved;
	NX_U8 create_time_millisecs;
	NX_U32 create_time_seconds:5;
	NX_U32 create_time_minutes:6;
	NX_U32 create_time_hours:5;
	NX_U32 create_date_day:5;
	NX_U32 create_date_month:4;
	NX_U32 create_date_year:7;
	NX_U32 laccess_date_day:5;
	NX_U32 laccess_date_month:4;
	NX_U32 laccess_date_year:7;
	NX_U16 first_cluster_hi;
	NX_U32 lmodify_time_seconds:5;
	NX_U32 lmodify_time_minutes:6;
	NX_U32 lmodify_time_hours:5;
	NX_U32 lmodify_date_day:5;
	NX_U32 lmodify_date_month:4;
	NX_U32 lmodify_date_year:7;
	NX_U16 first_cluster_lo;
	NX_U32 file_size;
} NX_PACKED;

#define FAT_LONGNAME_ATTRIBUTE		(0x0F)
#define FAT_LONGNAME_LASTSEQ_MASK	(0x40)
#define FAT_LONGNAME_SEQNO(s)		((s) & ~0x40)
#define FAT_LONGNAME_LASTSEQ(s) 	((s) & 0x40)
#define FAT_LONGNAME_MINSEQ			(1)
#define FAT_LONGNAME_MAXSEQ			(NX_FILE_MAX_NAME / 13)

/*
 * Directory long filename information for FAT12 / FAT16 / FAT32
 */
struct fat_longname_t {
	NX_U8 seqno;
	NX_U16 name_utf16_1[5];
	NX_U8 file_attributes;
	NX_U8 type;
	NX_U8 checksum;
	NX_U16 name_utf16_2[6];
	NX_U16 first_cluster;
	NX_U16 name_utf16_3[2];
} NX_PACKED;

#endif /* __FS_FAT_H__ */
